今天我們要學習Mock,在寫測試時,有些情況我們不想再測時執行某些方法,造成一些麻煩,我們希望這些方法有別的物件幫我們模擬出來,這時候我們可以用Mock幫我們。
今天我們要使用Mock,幫我們製造一些情境,我們回顧一下前面測試的store方法,發現到PDOException catch後的地方沒有測試到,我希望能夠將它寫進測試當中,但我想不到其他手段去製造PDOException的情境,因此,我們來製造一個替身,這個替身會幫我們製造PDOException,讓我們可辦法去預測catch後的結果。
來看一下我們的store方法
public function store(Request $request, UserService $userService)
{
$account = $request->account;
$password = $request->password;
$username = $request->username;
try{
if($userService->signUp($account, $password, $username)){
return response()->json([
'success' => 'true'
]);
}
} catch (PDOException $e){
return response()->json([
'success' => 'false',
'error'=> 'DB error'
]);
}catch (\Exception $e){
return response()->json([
'success' => 'false',
'error'=> $e->getMessage()
]);
}
}
我們若要捕捉到PDOException,我們需要讓$userService執行signUp時,丟出一個PDOException,有兩種方法,一種是真的製造這個情境(我想不到),另一種是利用Mock製造替身幫我們做。
希望呼叫store,在Service Provider再注入UserService時,不要放真身,而是製造一個替身放入,這個替身在執行signUp時,幫我們丟出PDOException
$this->mock(UserService::class, function (MockInterface $mock) {
$mock->shouldReceive('signUp')
->andThrow(new PDOException());
});
);
好我們的測試寫法如下,首先我們先製造一個mock在要注入UserService替換掉,接著就是執行動作,那在執行到signUp時,他會幫我們丟出PDOException,接著就catch並顯示結果。我們預期他會得到{
'success' => 'false',
'error'=> 'DB error'
}
/**
* @test
*/
public function storeGetPDOException()
{
//arrange
$this->mock(UserService::class, function (MockInterface $mock) {
$mock->shouldReceive('signUp')
->andThrow(new PDOException());
});
$id = 10;
$account = "JimChien";
$username = "Jim";
$password = "123Acb_";
// act&assert
$this->postJson("/api/user", [
'id'=>$id,
'account'=>$account,
'password'=>$password,
'username'=>$username
])
->assertStatus(200)
->assertJson([
'success' => 'false',
'error'=> 'DB error'
]);
}
好~!今天測試到這邊~~!